package modbus

import (
	"errors"
	"net"
	"sync"
	"time"
)

// ConnectionPool TCP连接池，提供连接复用功能
type ConnectionPool struct {
	mu          sync.RWMutex
	connections map[string]*pooledConnection
	maxIdle     int
	maxOpen     int
	idleTimeout time.Duration
	cleanup     *time.Ticker
	closed      bool
}

// pooledConnection 池化的连接
type pooledConnection struct {
	conn     net.Conn
	lastUsed time.Time
	inUse    bool
	created  time.Time
}

// ConnectionPoolConfig 连接池配置
type ConnectionPoolConfig struct {
	MaxIdleConnections int           // 最大空闲连接数
	MaxOpenConnections int           // 最大打开连接数
	IdleTimeout        time.Duration // 空闲超时时间
	CleanupInterval    time.Duration // 清理间隔
}

// DefaultConnectionPoolConfig 默认连接池配置
var DefaultConnectionPoolConfig = ConnectionPoolConfig{
	MaxIdleConnections: 10,
	MaxOpenConnections: 100,
	IdleTimeout:        5 * time.Minute,
	CleanupInterval:    1 * time.Minute,
}

// NewConnectionPool 创建新的连接池
func NewConnectionPool(config ConnectionPoolConfig) *ConnectionPool {
	pool := &ConnectionPool{
		connections: make(map[string]*pooledConnection),
		maxIdle:     config.MaxIdleConnections,
		maxOpen:     config.MaxOpenConnections,
		idleTimeout: config.IdleTimeout,
		cleanup:     time.NewTicker(config.CleanupInterval),
	}

	// 启动清理协程
	go pool.cleanupExpired()

	return pool
}

// GetConnection 获取连接
func (p *ConnectionPool) GetConnection(address string) (net.Conn, error) {
	p.mu.Lock()
	defer p.mu.Unlock()

	if p.closed {
		return nil, errors.New("connection pool is closed")
	}

	// 查找现有连接
	if pooled, exists := p.connections[address]; exists {
		if !pooled.inUse && time.Since(pooled.lastUsed) < p.idleTimeout {
			pooled.inUse = true
			pooled.lastUsed = time.Now()
			return pooled.conn, nil
		}
		// 连接已过期，清理
		pooled.conn.Close()
		delete(p.connections, address)
	}

	// 检查是否超过最大连接数
	if len(p.connections) >= p.maxOpen {
		return nil, errors.New("max open connections reached")
	}

	// 创建新连接
	conn, err := net.DialTimeout("tcp", address, 10*time.Second)
	if err != nil {
		return nil, err
	}

	p.connections[address] = &pooledConnection{
		conn:     conn,
		lastUsed: time.Now(),
		inUse:    true,
		created:  time.Now(),
	}

	return conn, nil
}

// ReturnConnection 归还连接
func (p *ConnectionPool) ReturnConnection(address string, conn net.Conn) {
	p.mu.Lock()
	defer p.mu.Unlock()

	if pooled, exists := p.connections[address]; exists && pooled.conn == conn {
		pooled.inUse = false
		pooled.lastUsed = time.Now()
	}
}

// CloseConnection 关闭连接
func (p *ConnectionPool) CloseConnection(address string) {
	p.mu.Lock()
	defer p.mu.Unlock()

	if pooled, exists := p.connections[address]; exists {
		pooled.conn.Close()
		delete(p.connections, address)
	}
}

// cleanupExpired 清理过期连接
func (p *ConnectionPool) cleanupExpired() {
	for range p.cleanup.C {
		p.mu.Lock()
		if p.closed {
			p.mu.Unlock()
			return
		}

		now := time.Now()
		for address, pooled := range p.connections {
			if !pooled.inUse && now.Sub(pooled.lastUsed) > p.idleTimeout {
				pooled.conn.Close()
				delete(p.connections, address)
			}
		}
		p.mu.Unlock()
	}
}

// Close 关闭连接池
func (p *ConnectionPool) Close() {
	p.mu.Lock()
	defer p.mu.Unlock()

	if p.closed {
		return
	}

	p.closed = true
	p.cleanup.Stop()

	for _, pooled := range p.connections {
		pooled.conn.Close()
	}
	p.connections = make(map[string]*pooledConnection)
}

// Stats 连接池统计信息
func (p *ConnectionPool) Stats() ConnectionPoolStats {
	p.mu.RLock()
	defer p.mu.RUnlock()

	stats := ConnectionPoolStats{
		TotalConnections: len(p.connections),
	}

	for _, pooled := range p.connections {
		if pooled.inUse {
			stats.ActiveConnections++
		} else {
			stats.IdleConnections++
		}
	}

	return stats
}

// ConnectionPoolStats 连接池统计
type ConnectionPoolStats struct {
	TotalConnections  int
	ActiveConnections int
	IdleConnections   int
}

// PooledTCPClientProvider 支持连接池的TCP客户端提供者
type PooledTCPClientProvider struct {
	*TCPClientProvider
	pool *ConnectionPool
}

// NewPooledTCPClientProvider 创建支持连接池的TCP客户端
func NewPooledTCPClientProvider(address string, opts ...ClientProviderOption) *PooledTCPClientProvider {
	provider := &PooledTCPClientProvider{
		TCPClientProvider: NewTCPClientProvider(address, opts...),
		pool:              NewConnectionPool(DefaultConnectionPoolConfig),
	}
	return provider
}

// NewPooledTCPClientProviderWithPool 使用指定连接池创建TCP客户端
func NewPooledTCPClientProviderWithPool(address string, pool *ConnectionPool, opts ...ClientProviderOption) *PooledTCPClientProvider {
	provider := &PooledTCPClientProvider{
		TCPClientProvider: NewTCPClientProvider(address, opts...),
		pool:              pool,
	}
	return provider
}

// Connect 连接（使用连接池）
func (sf *PooledTCPClientProvider) Connect() error {
	conn, err := sf.pool.GetConnection(sf.address)
	if err != nil {
		return err
	}

	// 设置连接到TCP客户端提供者
	sf.mu.Lock()
	if sf.conn != nil {
		sf.pool.ReturnConnection(sf.address, sf.conn)
	}
	sf.conn = conn
	sf.mu.Unlock()

	return nil
}

// Close 关闭连接（归还到池中）
func (sf *PooledTCPClientProvider) Close() error {
	sf.mu.Lock()
	defer sf.mu.Unlock()

	if sf.conn != nil {
		sf.pool.ReturnConnection(sf.address, sf.conn)
		sf.conn = nil
	}
	return nil
}

// GetConnectionPool 获取连接池实例
func (sf *PooledTCPClientProvider) GetConnectionPool() *ConnectionPool {
	return sf.pool
}

// NewPooledClient 创建使用连接池的客户端
func NewPooledClient(address string, opts ...Option) Client {
	provider := NewPooledTCPClientProvider(address)
	return NewClient(provider, opts...)
}

// NewHighPerformancePooledClient 创建高性能连接池客户端
func NewHighPerformancePooledClient(address string, opts ...Option) HighPerformanceClient {
	provider := NewPooledTCPClientProvider(address)
	return NewHighPerformanceClient(provider, opts...)
}
